// 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串，则返回空字符串 "" 。

// 注意：如果 s 中存在这样的子串，我们保证它是唯一的答案。



// 示例 1：
// 输入：s = "ADOBECODEBANC", t = "ABC"
// 输出："BANC"


// 示例 2：
// 输入：s = "a", t = "a"
// 输出："a"



/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function (s, t) {
// ============================初始化===================================
    let
        // 左右指针
        left = 0,
        right = 0,
        // window中满足need中字符条件的个数
        valid = 0,
        // need标准模板（哈希表），此处是{A:1,B:1,c:1}
        // window滑动窗口，记录实时的匹配情况（哈希表）。{A:0,B:0,C:0}
        need = {},
        window = {};
    // 初始化need，window
    t.split('').forEach(item => {
        if (need[item] === undefined) {
            need[item] = 1;
        } else {
            need[item]++;
        }
        if (window[item] === undefined) {
            window[item] = 0;
        }
    });
    // 初始化最终的结果：连续字串的起始下标start，子串长度len
    let
        start = 0,
        len = Number.MAX_SAFE_INTEGER;
// ============================滑动===================================
    // [left,right)子串区间左闭右开
    // 外层while，每次循环控制right的滑动
    while (right < s.length) {
        // 每次滑动right前，记录当前right
        let right_curchar = s[right];
        // 滑动right
        right++;
        // 对滑动操作进行更新相关的变量
        // 如果新增right是need中需要的
        if (need[right_curchar] !== undefined) {
            // 更新window[相应]
            window[right_curchar]++;
            // 如果window中[相应]的数量达到了need中的需求，则更新valid
            // 若[相应]的数量后续超过了，不会更新valid
            if (need[right_curchar] === window[right_curchar]) {
                valid++;
            }
        }
        // 内层while，滑动left
        // 当滑动right到刚好包含了t字符串，开始滑动left收缩区间
        // 若不滑动left，则获得的字串不是最优，收缩left旨在找到最小字串
        while (valid === [...Object.keys(need)].length) {
            // 此时获得的字串若比最终结果记录更短，则优，则更新结果
            let curLen = right - left;
            if (curLen < len) {
                start = left;
                len = curLen;
            }
            // 每次滑动right前，记录当前left
            let left_curchar = s[left];
            // 滑动left
            left++;
            // 每一次滑动left，移除一个元素，更新
            if (need[left_curchar] !== undefined) {
                if (window[left_curchar] === need[left_curchar]) {
                    valid--;
                }
                window[left_curchar]--;
            }
        }
    }
    return (len === Number.MAX_SAFE_INTEGER) ? '' : s.substr(start, len);
};




// 测试用例
let s = 'ADOBECODEBANC',
    t = 'ABC';
console.log(minWindow(s, t))